import hashlib
import json
import os
import time
import sys
import select
import machine
import network
import ujson
import usocket
import urequests
from machine import Pin, ADC
import _thread
import uos
import ntptime
 
# ============================================================================================
# 文件相关、时间相关
def now():
    return int(time.time())

def format_date(timestamp: int) -> str:
    # 将时间戳转换为本地时间
    l = time.localtime(timestamp)
    # 格式化为 "YYYY-MM-DD" 字符串
    return "{:04d}-{:02d}-{:02d}".format(l[0], l[1], l[2])

def format_datetime(timestamp: int) -> str:
    # 将时间戳转换为本地时间
    l = time.localtime(timestamp)
    # 格式化为 "YYYY-MM-DD HH:MM:SS" 字符串
    return "{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(l[0], l[1], l[2], l[3], l[4], l[5])

def is_file(path):
    try:
        # 获取路径的状态
        stat_info = os.stat(path)
        # 判断是否为文件（通过文件模式来判断）
        if stat_info[0] & 0x4000:  # 0x4000 是文件的标志位
            return False
        else:
            return True
    except OSError:
        return False  # 如果路径不存在，则返回 False

def create_folder_if_not_exists(path):
    try:
        # 尝试获取目录的状态，如果路径存在，会返回状态信息
        os.stat(path)
        print("目录已存在")
    except OSError:
        os.mkdir(path)
        print("目录已创建")

def check_file_exists(file_path):
    try:
        os.stat(file_path)
        return True
    except OSError:
        return False
    
# 删除文件
def remove_file(file_path):
    try:
        if check_file_exists(file_path):
            os.remove(file_path)
            print(f"文件 {file_path} 已删除")
        else:
            print(f"文件 {file_path} 不存在")
    except OSError as e:
        print(f"无法删除文件 {file_path}: {e}")

def ls_la(directory):
    # 检查目录是否存在
    if not check_file_exists(directory):
        print(f"目录 {directory} 不存在")
        return
    #try:
    # 列出目录中的所有文件和文件夹
    files = os.listdir(directory)
    
    for file in files:
        # 获取文件的完整路径
        file_path = directory + '/' + file
        
        # 获取文件的状态信息
        file_stat = os.stat(file_path)
        
        # 获取文件的权限
        permissions = oct(file_stat[0])[-3:]
        
        # 获取文件大小
        file_size = file_stat[6]
        
        # 获取文件的最后修改时间
        last_modified_str = format_datetime(file_stat[8])
        
        # 打印文件信息
        print(f"{permissions} {file_size:10} {last_modified_str} {file}")
    
    # except Exception as e:
    #     print(f"Error: {e}")

# ============================================================================================
# TSData相关
DATA_FILE_FOLDER = 'elec_data'

# 定义常量
SECOND_STEP = 1  # 间隔多少秒记录一个数据
DATA_SIZE = 1  # 每个数据块字节大小
SECONDS_IN_DAY = 86400
DATA_COUNT_IN_DAY = SECONDS_IN_DAY // SECOND_STEP
DATA_RANGE = 2**(8*DATA_SIZE) - 1
FILE_SIZE = DATA_COUNT_IN_DAY * DATA_SIZE  # 文件总大小为86400 * 2字节

class TSData:
    INVILD_VALUE = DATA_RANGE

    @staticmethod
    def write_now(value: int, data_dir: str):
        # 计算当前在一天中的总秒数
        seconds_today = now() % 86400
        index = seconds_today // 3600
        second = seconds_today % 3600
        # 生成文件名
        file_dir = data_dir + '/' + format_date(now())
        if not check_file_exists(file_dir):
            create_folder_if_not_exists(file_dir)
            for i in range(0, 36):
                file_name = file_dir + '/' + str(i) + '.bin'
                with open(file_name, 'wb') as f:
                    f.write(b'\xff' * 3600)
                    print(f"File {file_name} created with size 3600 bytes")
        file_name = file_dir + '/' + str(index) + '.bin'
        # 将值写入到文件
        with open(file_name, 'r+b') as f:
            # 计算偏移量（每个数据块为2字节）
            offset = (second // SECOND_STEP) * DATA_SIZE
            # 移动文件指针到指定位置
            f.seek(offset)
            # 写入数据
            data = value.to_bytes(DATA_SIZE, 'big')
            f.write(data)

# ================================================================================
# 配置相关
        
# 配置文件路径
config_file = 'config.json'

# 默认配置
default_config = {
    'client_id': 'esp32_client',
    'server_ip': '192.168.1.100',
    'server_port': '8080',
    'wifi_name': 'dandanliang',
    'wifi_password': '159753wifi',
    'upload_interval': '5',
    'sync_time_api': '/api/sync_time',
    'check_upload_api': '/api/check_elec_upload',
    'upload_day_data_api': '/api/upload_elec_data',
    'upload_current_data_api': '/api/upload_elec_current',
    'adc_poly_a': '0', 
    'adc_linear_b': '0.99',
    'adc_offset_c': '0.68',
    'remark': '',
    'ip_mode': 'dhcp',
    'ip': '192.168.1.146',
    'netmask': '255.255.255.0',
    'gateway': '192.168.1.1',
    'dns': '8.8.8.8',
}

def print_config(config):
    print('------------------------')
    print("Loaded configuration:")
    for key, value in config.items():
        print(f"{key}={value}")
    print('------------------------')
# 加载配置函数
def load_config(force=False):
    try:
        if force:
            with open(config_file, 'r') as f:
                config = ujson.load(f)
            for key, value in default_config.items():
                if config.get(key) is None:
                    pass
                else:
                    default_config[key] = config[key]
        return default_config
    except OSError:
        print("No config file found, using default config.")
        return default_config

# 保存配置函数
def save_config(config):
    with open(config_file, 'w') as f:
        ujson.dump(config, f)

# 通过串口接收配置并更新配置文件
def configure_via_serial():
    print("Entering configuration mode...")
    config = load_config()
    print_config(config)

    while True:
        line = input("Enter configuration (or save/exit): ").strip()
        if line.lower() == "exit":
            break
        elif line.lower() == "save":
            save_config(config)
            print("Configuration saved.")
            print_config(config)
            break
        else:
            try:
                key, value = line.split("=")
                if key in default_config:
                    config[key] = value
                    print(f"Updated {key} to {value}")
                else:
                    print(f"Invalid key: {key}")
            except ValueError:
                print("Invalid input format. Use key=value format.")

# ================================================================================
# wifi网络相关
def set_led(state):
    led = Pin(2, Pin.OUT)
    led.value(state)

# 连接WiFi
def connect_wifi(config, force=False):
    try:
        wifi = network.WLAN(network.STA_IF)
        wifi.active(True)
        if wifi.isconnected() and not force:
            return True
        else:
            wifi.disconnect()
        print('Connecting to WiFi...')
        wifi.connect(config['wifi_name'], config['wifi_password'])
        test_count = 0
        while not wifi.isconnected() and test_count < 10:
            test_count += 1
            time.sleep(1)
        if wifi.isconnected():
            set_led(1)
            if config['ip_mode'] == 'dhcp':
                print('WiFi connected:', wifi.ifconfig())
                return True
            elif wifi_set_static_ip(config, wifi): # 如果静态IP设置成功
                print('WiFi connected with static IP:', wifi.ifconfig())
                return True
            else:
                print('WiFi connected:', wifi.ifconfig()) # 如果静态IP设置失败，则返回打印DHCP配置
                return True
        else:
            print('Failed to connect to WiFi.')
            set_led(0)
            return False
    except Exception as e:
        print('Error connecting to WiFi:', e)
        set_led(0)
        return False

def wifi_set_static_ip(config, wifi):
    # 尝试设置静态IP（这可能不会在所有MicroPython固件上都有效）
    # 注意：下面的代码可能不会改变IP地址，取决于固件的实现
    try:
        # 假设你想要设置的静态IP是'192.168.1.100'，子网掩码是'255.255.255.0'
        # 网关和DNS服务器可能需要根据你的网络配置来设置
        ip = config['ip']
        netmask = config['netmask']
        gateway = config['gateway']
        dns_server = config['dns']
        
        # 注意：下面的调用可能不会生效，取决于你的MicroPython固件
        wifi.ifconfig((ip, netmask, gateway, dns_server))
        
        # 打印新的配置以检查是否更改成功
        print('New network config:', wifi.ifconfig())
        return True
    except AttributeError:
        # 如果ifconfig方法不接受参数，则会抛出AttributeError
        print('Static IP setting not supported by this MicroPython firmware.')
        return False

# wifi状态
def wifi_status():
    # 获取 Wi-Fi 接口
    wifi = network.WLAN(network.STA_IF)

    message = ""
    # 检查是否已连接
    if wifi.isconnected():
        message += "已连接到 Wi-Fi"
        
        # 获取 SSID
        ssid = wifi.config("essid")
        message += "\nSSID: " + ssid
        
        # 获取信号强度 (RSSI)
        rssi = wifi.status("rssi")
        message += "\n信号强度 (RSSI): " + str(rssi) + " dBm"
        
        # 获取 MAC 地址
        mac = wifi.config("mac")
        message += "\nMAC 地址: " + ":".join("{:02x}".format(b) for b in mac)
        
        # 获取 IP 地址信息
        ip_info = wifi.ifconfig()
        message += "\nIP 地址: " + ip_info[0]
        message += "\n子网掩码: " + ip_info[1]
        message += "\n网关: " + ip_info[2]
        message += "\nDNS: " + ip_info[3]
    else:
        message += "未连接到 Wi-Fi"

    return message


def check_storage():
    # 获取文件系统的状态信息
    stat = os.statvfs('/')
    
    # 计算存储空间相关信息
    block_size = stat[0]  # 块大小（字节）
    total_blocks = stat[1]  # 总块数
    free_blocks = stat[2]   # 空闲块数
    available_blocks = stat[3]  # 可用块数（用于非root用户）
    
    total_space = block_size * total_blocks  # 总空间（字节）
    free_space = block_size * free_blocks  # 空闲空间（字节）
    available_space = block_size * available_blocks  # 可用空间（字节）

    # 打印输出详细信息
    message = ''
    message += "存储信息:"
    message += f"\n块大小: {block_size} 字节"
    message += f"\n总块数: {total_blocks}"
    message += f"\n总空间: {total_space / (1024 * 1024):.2f} MB"
    message += f"\n空闲块数: {free_blocks}"
    message += f"\n空闲空间: {free_space / (1024 * 1024):.2f} MB"
    message += f"\n可用块数: {available_blocks}"
    message += f"\n可用空间: {available_space / (1024 * 1024):.2f} MB"
    return message

# ================================================================================
# 模拟量相关
# 读取模拟量并计算电压值
def read_analog(config):
    adc = ADC(Pin(34))  # 假设模拟输入连接在GPIO34
    adc.atten(ADC.ATTN_11DB)  # 0-3.3V
    adc.width(ADC.WIDTH_12BIT)  # 12-bit精度
    raw_value = adc.read()
    voltage = 0
    if raw_value > 0:
        adc_poly_a = float(config['adc_poly_a'])
        adc_linear_b = float(config['adc_linear_b'])
        adc_offset_c = float(config['adc_offset_c'])
        voltage = (raw_value / 4095.0) * 3.3  # 假设3.3V参考电压
        voltage = voltage * 5 # 假设电压放大5倍
        print(adc_poly_a, adc_linear_b, voltage)
        voltage = adc_poly_a * voltage ** 2 + adc_linear_b * voltage + adc_offset_c
        voltage = voltage * 2
    # 保留一位小数
    voltage = round(voltage, 1)
    return voltage

# 使用 HTTP 协议上传数据
def upload_data_http(config, voltage, datetime_str):
    url = f"http://{config['server_ip']}:{config['server_port']}/{config['upload_current_data_api']}"
    headers = {
        'Content-Type': 'application/json',
        'Client-ID': config['client_id']
    }
    payload = {
        'voltage': voltage,
        'client_id': config['client_id'],
        'datetime': datetime_str
    }
    try:
        response = urequests.post(url, json=payload, headers=headers, timeout=5)
        if response.status_code == 200:
            if response.json()['status'] == 'ok':
                print(f"Data uploaded. Response: {response.status_code}")
                response.close()
            elif response.json()['status'] == 'error':
                if response.json()['tag'] == 'sync_time':
                    # 时间不同步，需要同步时间
                    print("Time is not synchronized. Syncing time...")
                    sync_time(config)
                response.close()
        else:
            print(f"Failed to upload data. Response: {response.status_code}")
            response.close()
    except Exception as e:
        print(f"Failed to upload data: {e}")

def set_system_time(current_time_str):
    # 初始化 RTC
    rtc = machine.RTC()
    # 解析时间字符串
    year = int(current_time_str[0:4])        # 2025
    month = int(current_time_str[5:7])       # 2
    day = int(current_time_str[8:10])       # 25
    hour = int(current_time_str[11:13])     # 12
    minute = int(current_time_str[14:16])   # 30
    second = int(current_time_str[17:19])   # 24
    # 设置系统时间
    # 注意：weekday 可以设置为 None，系统会自动计算
    rtc.datetime((year, month, day, None, hour, minute, second, 0))
    # 读取并打印当前系统时间
    current_time = rtc.datetime()
    print("设置后的系统时间:", current_time)
    print("System time set successfully!")

def sync_time_ntp():
    # NTP服务器和时间同步
    ntp_server = "pool.ntp.org"  # 可以使用其他可靠的NTP服务器
    timezone_sec = 3600 * 8       # UTC+8时区偏移量，例如中国标准时间
    
    # 同步RTC时间（注意：这将覆盖RTC的当前时间）
    try:
        ntptime.settime()  # 同步时间
        current_time_str = format_datetime(time.time() + 8 * 3600) # 转换为北京时间
        set_system_time(current_time_str)
        print("Time synchronized with NTP server")
    except Exception as e:
        print("Failed to synchronize time:", e)

# 时间同步
def sync_time(config):
    api_url = f'http://{config["server_ip"]}:{config["server_port"]}{config["sync_time_api"]}'
    """
    从指定的 API 获取时间，并设置 ESP32 系统时间。
    
    :param api_url: 时间 API 的 URL，返回格式类似 "2025-02-15 08:41:23"
    """
    try:
        # 发送 GET 请求获取时间
        print("Getting time from API...")
        response = urequests.get(api_url, timeout=5)
        data = response.json()  # 解析 JSON 响应
        if not data or data['status'] != 'ok':
            print("Failed to get time from API.")
            # 通过时间服务器连接
            sync_time_ntp()
            return
        current_time_str = data["datetime"]  # 假设响应中的时间字段是 'datetime'
        print("Current time from API:", current_time_str) 
        set_system_time(current_time_str)
        return True

    except Exception as e:
        print("Failed to get or set time:", e)
        sync_time_ntp()
        return False

# 计算文件的 MD5 值
def calculate_md5(file_dir):
    # 创建一个 MD5 哈希对象
    md5_hash = hashlib.md5()
    try:
        # 打开文件进行二进制读取
        for i in range(0, 36):
            file_path = file_dir + '/' + str(i) + '.bin'
            with open(file_path, 'rb') as f:
                chunk = f.read()
                md5_hash.update(chunk)
        # 获取文件的 MD5 值（使用 digest 方法）
        md5_value = md5_hash.digest()  # 返回 MD5 值的二进制结果
        # 将 MD5 值转换为十六进制字符串
        result = hex(int.from_bytes(md5_value))[2:] #''.join([hex(byte)[2:] for byte in md5_value])
        print(result)
        return result
    
    except Exception as e:
        print(f"计算 MD5 时发生错误: {e}")
        return None

def upload_elec_file(config, date_str: str, check: bool = True):
    file_dir = f'{DATA_FILE_FOLDER}/{date_str}'
    if not check_file_exists(file_dir):
        print(f"File {file_dir} does not exist.")
        return False, "File does not exist."
    # 计算文件的 MD5 值
    file_hash = calculate_md5(file_dir)

    try:
        # 检查文件是否已上传
        url_check = f'http://{config["server_ip"]}:{config["server_port"]}{config["check_upload_api"]}'
        response_check = urequests.post(url_check, json={
            'client_id': config['client_id'], 
            'data_date': date_str, 
            'file_hash': file_hash
        }, headers={
            "Content-Type": "application/json" 
        })

        if response_check.status_code == 200 and response_check.json()['status'] == 'ok':
            print("File already uploaded, skipping upload.")
            return True, "File already uploaded."
        
        # 打开文件
        chunk_total = 36
        for chunk_index in range(1, chunk_total+1):
            file_path = file_dir + '/' + str(chunk_index-1) + '.bin'
            with open(file_path, 'rb') as file:
                file_data = file.read()

                # 构造multipart/form-data 请求头
                boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"  # 自定义边界字符串
                headers = {
                    "Content-Type": "multipart/form-data; boundary=" + boundary
                }
                params = {'client_id': config['client_id'], 'data_date': date_str, 'trunk': 1, 'trunk_index': chunk_index, 'trunk_total': chunk_total, 'file_hash': file_hash }  # 添加普通表单参数， trunk为1表示是分片上传，为0表示是完整上传
                # 构造请求体（包括文件和普通表单参数）
                body = b""  # 使用字节串初始化请求体
                # 添加普通表单参数（如 client_id, user_id）
                for key, value in params.items():
                    body += (
                        f"--{boundary}\r\n"
                        f"Content-Disposition: form-data; name=\"{key}\"\r\n\r\n"
                        f"{value}\r\n".encode()  # 转换为字节
                    )
                # 添加文件数据
                body += (
                    f"--{boundary}\r\n"
                    f"Content-Disposition: form-data; name=\"file\"; filename=\"{file_path}\"\r\n"
                    f"Content-Type: application/octet-stream\r\n\r\n".encode()
                )
                body += file_data  # 直接将文件字节数据添加到请求体中
                body += (
                    f"\r\n--{boundary}--\r\n".encode()  # 结束边界
                )
                # 上传文件
                url_upload = f'http://{config["server_ip"]}:{config["server_port"]}{config["upload_day_data_api"]}'
                response_upload = urequests.post(url_upload, data=body, headers=headers)
                if response_upload.status_code == 200:
                    if response_upload.json()['status'] == 'ok':
                        print(f"Uploaded chunk {chunk_index}/{chunk_total}.")
                        if chunk_index == chunk_total:
                            print(response_upload.json())
                            print("File uploaded successfully.")
                            return True, "File uploaded successfully."
                        else:
                            continue
                    else:
                        print(response_upload.json()['msg'])
                        return False, "Failed to upload file."
                else:
                    print("Failed to upload file.")
                    return False, "Failed to upload file."
    except Exception as e:
        print("Error:", e)
        return False, "Error occurred during upload."

def get_user_date_input():
    # 获取用户输入的日期字符串
    user_input = input("请输入日期（格式：YYYY-MM-DD）：")
    try:
        return user_input
    except ValueError:
        print("输入的日期格式不正确，请使用 YYYY-MM-DD 格式。")
        return None

def upload_date_elec_file(config):
    date_str = get_user_date_input()
    return upload_elec_file(config, date_str)

def upload_yesterday_elec_file(config):
    date_str = format_date(now() - 86400)  # 获取昨天的日期
    return upload_elec_file(config, date_str)

def upload_today_elec_file(config):
    date_str = format_date(now())  # 获取今天的日期
    return upload_elec_file(config, date_str, False)

# 上传前几日的数据
def upload_before_elec_file(config, prev_days = 7):
    today = now()
    for i in range(1,prev_days+1):
        date_str = format_date(today - i * 86400)
        upload_elec_file(config, date_str)

def handle_upload(config, date_str):
    if date_str is not None:
        if date_str == 'yesterday':
            return upload_yesterday_elec_file(config)
        elif date_str == 'today':
            return upload_today_elec_file(config)
        else:
            return upload_elec_file(config, date_str)
    else:
        return upload_date_elec_file(config)

def delete_folder_and_contents(folder_path):
    try:
        # 列出文件夹中的所有项
        items = uos.listdir(folder_path)
        for item in items:
            # 构建完整路径
            item_path = folder_path + '/' + item
            # 检查是否是文件夹
            if uos.stat(item_path)[0] & 0x4000:  # 0x4000表示是文件夹
                # 递归删除子文件夹及其内容
                delete_folder_and_contents(item_path)
            else:
                # 删除文件
                uos.remove(item_path)
        # 删除空文件夹本身
        uos.rmdir(folder_path)
    except OSError as e:
        print(f"Error deleting folder {folder_path}: {e}")
        
def delete_old_files(prev_days=7):
    """
    删除指定文件夹中一周前的文件
    """
    root_path = DATA_FILE_FOLDER  # 指定文件夹路径
    
    limit_time = now() - (prev_days * 24 * 60 * 60)  # 7 天的秒数
    limit_name = format_date(limit_time)
    
    print(f"Deleting files older than {limit_name}")
    # 列出根目录下的所有项
    items = uos.listdir(root_path)
    for item in items:
        # 构建完整路径
        item_path = root_path + '/' + item
        # 检查是否是文件夹
        if uos.stat(item_path)[0] & 0x4000:  # 0x4000表示是文件夹
            # 检查是否满足条件
            if item <= limit_name:
                # 删除文件夹及其内容
                delete_folder_and_contents(item_path)
                print(f"Deleted folder: {item_path}")

# ===================================================================================
# 提供 api 供外部调用
# 定义HTTP服务器的IP地址和端口
SERVER_ADDRESS = ('', 80)
 
def http_response(status_code, headers, body):
    """构造HTTP响应"""
    response = f"HTTP/1.1 {status_code} OK\r\n"
    for key, value in headers.items():
        response += f"{key}: {value}\r\n"
    response += "\r\n" + body
    return response.encode('utf-8')

def parse_query_string(query_string):
    """解析查询字符串"""
    params = {}
    for param in query_string.split('&'):
        key, value = param.split('=')
        params[key] = value
    return params

letters_and_nums = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
def urldecode(encoded_str):
    decoded_bytes = bytearray()
    i = 0
    while i < len(encoded_str):
        if encoded_str[i] == '%':
            if i + 2 < len(encoded_str) and encoded_str[i + 1] in letters_and_nums and encoded_str[i + 2] in letters_and_nums:
                hex_digits = encoded_str[i + 1:i + 3]
                decoded_bytes.append(int(hex_digits, 16))
                i += 2
        elif encoded_str[i] == '+':
            decoded_bytes.append(ord(' '))
        else:
            decoded_bytes.append(ord(encoded_str[i]))
        i += 1
    return decoded_bytes.decode('utf-8')

def handle_request(method, uri, params):
    headers = {
        'Content-Type': 'text/plain',
        'Connection': 'close'
    }
    if uri == '/voltage':
        # 处理电压数据请求
        body = json.dumps({'voltage': last_voltage, 'time': last_update_time})
        return http_response(200, headers, body)
    elif uri == '/ifconfig':
        body = wifi_status()
        return http_response(200, headers, body)
    elif uri == '/config':
        # 处理配置请求
        config = load_config()
        config = json.loads(json.dumps(config))
        config['wifi_password'] = '********'
        body = json.dumps(config)
        return http_response(200, headers, body)
    elif uri == '/set_config':
        # 处理设置配置请求
        config = load_config()
        for key, value in params.items():
            if key in config:
                config[key] = urldecode(value)
        save_config(config)
        body = "Config updated"
        return http_response(200, headers, body)
    elif uri == '/storage':
        body = check_storage()
        return http_response(200, headers, body)
    elif uri == '/reconnect_wifi':
        # 处理重新连接WiFi请求
        config = load_config()
        if connect_wifi(config):
            body = "WiFi reconnected"
        else:
            body = "WiFi reconnect failed"
        return http_response(200, headers, body)
    elif '/upload' in uri:
        temp = uri.split('/')
        if len(temp) > 2:
            date_str = temp[2]
            config = load_config()
            status, msg = handle_upload(config, date_str)
            if status:
                body = "Upload successful"
            else:
                body = msg
            return http_response(200, headers, body)
        else:
            body = "Please use correct uri format, such as /upload/2023-01-01, or /upload/today or /upload/yesterday"
            return http_response(400, headers, body)
    elif uri == '/test':
        # 处理测试请求
        body = "Test response"
        return http_response(200, headers, body)
    else:
        # 对于不支持的URI，返回404错误
        body = "404 Not Found"
        return http_response(404, headers, body)

def handle_client(client_socket):
    """处理客户端连接"""
    request = client_socket.recv(1024).decode('utf-8')
    print("Received request:")
    print(request)
    
    # 分割请求行和请求头
    lines = request.split('\r\n')
    request_line = lines[0]
    headers_raw = '\r\n'.join(lines[1:-1]) if len(lines) > 1 else ''
    
    # 解析请求行
    request_method, request_uri, http_version = request_line.split(' ')
    
    # 对于GET请求，解析查询字符串
    if request_method == 'GET':
        temp = request_uri.split('?')
        parsed_uri = temp[0]
        query_params = {}
        if len(temp) > 1:
            query_params = parse_query_string(temp[1])
        
        # 构造响应
        response = handle_request(request_method, parsed_uri, query_params)
    else:
        # 对于不支持的请求方法，返回405错误
        headers = {
            'Allow': 'GET',
            'Content-Type': 'text/plain',
            'Connection': 'close'
        }
        body = "405 Method Not Allowed"
        response = http_response(405, headers, body)
    
    client_socket.send(response)
    client_socket.close()

def start_http_server():
    """启动HTTP服务器"""
    addr = SERVER_ADDRESS
    sock = usocket.socket()
    
    sock.bind(addr)
    sock.listen(1)
    print('Listening on', addr)
    
    while True:
        try:
            conn, addr = sock.accept()
            print('Accepted connection from', addr)
            handle_client(conn)
        except Exception as e:
            print('Error handling client:', e)
    


# ===================================================================================
# 主线程
last_voltage = 0 # 上一次的电压值
last_update_time = None # 上一次更新时间

last_execution_time_upload = time.time()
last_execution_time_60 = time.time()
last_execution_time_300 = time.time()
last_execution_time_3600 = time.time()
# global_task
def global_task():
    global last_voltage, last_update_time, last_execution_time_upload, last_execution_time_60, last_execution_time_300, last_execution_time_3600
    while True:
        config = load_config()  # 加载配置
        if time.time() - last_execution_time_upload >= int(config['upload_interval']):
            last_execution_time_upload = time.time()
            # 上传数据，如果网络连接正常
            if network.WLAN(network.STA_IF).isconnected():
                if last_update_time != None:
                    set_led(0)
                    upload_data_http(config, last_voltage, last_update_time)  # 上传数据
                    set_led(1)
            else:
                set_led(0)
        if now() - last_execution_time_60 >= 60: # 每分钟检查一次网络连接
            last_execution_time_60 = time.time()
            if not network.WLAN(network.STA_IF).isconnected():
                # 如果网络连接不正常，则每分钟尝试重新连接一次
                set_led(0)
                if connect_wifi(config):
                    set_led(1)
                sync_time(config) # 同步时间
            else:
                set_led(1)
        if now() - last_execution_time_300 >= 300:
            last_execution_time_300 = time.time()
            sync_time(config) # 每5分钟同步一次时间
        if now() - last_execution_time_3600 >= 3600:
            last_execution_time_3600 = time.time()
            delete_old_files() # 每小时删除一次旧文件
            # upload_yesterday_elec_file(config) # 每小时上传一次昨天的数据
            upload_before_elec_file(config) # 每小时上传一次前七天数据
        time.sleep(1)

# 主程序
def main():
    global last_voltage, last_update_time
    config = load_config()  # 加载配置
    try:
        while True:
            # 检查串口输入(非阻塞，当有输入时，开始阻塞，直到点击enter)
            rlist, _, _ = select.select([sys.stdin], [], [], 0)
            if rlist:
                user_input = sys.stdin.readline().strip()  # 获取用户输入
                last_update_time = None # 清空上一次更新时间，暂停上传，此时也会停止采集数据
                print("--------------------------------------------")
                print("Available commands: config, ifconfig, delete_old_files, exit, ls, reconnect_wifi, rm, storage, sync_time, upload, time")
                while True: # 循环处理用户输入
                    # 提示可以输入什么命令
                    user_input = input("Enter your command: ")
                    args = user_input.lower().strip().split(' ')
                    if args[0] == 'exit':
                        break
                    elif args[0] == 'config':
                        configure_via_serial() # 配置
                        config = load_config(True)  # 重新加载配置
                    elif args[0] == 'reconnect_wifi':
                        connect_wifi(config)
                    elif args[0] == 'upload':
                        if len(args) > 1:
                            handle_upload(config, args[1])
                        else:
                            handle_upload(config, None)
                    elif args[0] == 'sync_time':
                        sync_time(config)
                    elif args[0] == 'delete_old_files':
                        if len(args) > 1:
                            delete_old_files(int(args[1]))
                        else:
                            delete_old_files()
                    elif args[0] == 'ls':
                        if len(args) > 1:
                            ls_la(args[1])
                        else:
                            ls_la('.')
                    elif args[0] == 'storage':
                        print(check_storage())
                    elif args[0] == 'rm':
                        if len(args) > 1:
                            remove_file(args[1])
                        else:
                            print("Please specify a file to remove")
                    elif args[0] == 'time':
                        print(format_datetime(now()))
                    elif args[0] == 'ifconfig':
                        print(wifi_status())
                    else:
                        print("Unknown command")
                print("--------------------------------------------")

            # 读取电压值
            datetime_str = format_datetime(now())
            if last_update_time == datetime_str:
                continue
            voltage = read_analog(config)  # 读取电压
            print(f"[{datetime_str}] Voltage: {voltage} V")
            save_voltage = int(voltage * 10)
            if save_voltage < 0:
                save_voltage = 0
            if save_voltage > 252:
                save_voltage = 252
            # 保存电压值
            TSData.write_now(save_voltage, DATA_FILE_FOLDER)
            last_voltage = voltage
            last_update_time = datetime_str
            
            time.sleep(0.5)
    except KeyboardInterrupt:
        print("Program terminated")
    except Exception as e:
        print(f"An error occurred: {e}")

# 程序入口
if True or __name__ == '__main__':
    # 检查并创建 'elec_data' 文件夹
    create_folder_if_not_exists(DATA_FILE_FOLDER)

    config = load_config(True)  # 加载配置
    print_config(config) # 打印配置
    connect_wifi(config)  # 连接WiFi
    sync_time(config)  # 同步时间
    
    # 启动全局任务
    _thread.start_new_thread(global_task, ())

    # 启动HTTP服务器
    _thread.start_new_thread(start_http_server, ())

    # 主程序
    main()